package org.csu.linkgame.service.ClassForDoubleGame;

import javafx.animation.*;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Bounds;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
import javafx.scene.effect.Glow;
import javafx.scene.paint.Color;
import javafx.scene.shape.LineTo;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.Path;
import javafx.scene.text.Text;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.util.Duration;
import org.csu.linkgame.LinkGameApplication;
import org.csu.linkgame.domain.User;
import org.csu.linkgame.service.dgService;


import java.io.Serializable;
import java.net.Socket;
import java.sql.*;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.Date;

public class dgServiceImpl extends Group implements dgService, Serializable {
    static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
    static final String DB_URL = "jdbc:mysql://localhost:3306/super_link?useUnicode=true&characterEncoding=utf8";


    // 数据库的用户名与密码，需要根据自己的设置
    static final String USER = "root";
    static final String PASS = "2003052288mjp";
    // 存储剩余的Uint
    public Map<dgPoint, dgTile> map = new HashMap<>();
    // 存储Uint对应的Bound
    public Map<dgPoint, dgBound> boundMap = new HashMap<>();

    // 开始Unit
    public dgTile tempStart;
    // 目标Unit
    public dgTile tempEnd;

    // 用于保存查找的可行解,也即可行路径
    private LinkedList<dgPoint> resultPath = new LinkedList<>();
    // LinkedList是一个类似于ArrayList的列表，但它在充当队列queue和栈stack的时候有很好的效果
    // 不过这里主要是看网上的参考代码时，网上用的就是LinkedList，所以就参考着写了

    public int randomRow;
    public int randomCol;
    public Socket socket;
    User user;
    public void setUser(User user) {
        this.user = user;
    }
    public dgServiceImpl() {
        initGame();
    }
    public dgServiceImpl(List<Integer> randomRowList,List<Integer> randomColList) throws Exception {
        Connection conn = null;
        Statement stmt = null;

        // 注册 JDBC 驱动
        Class.forName(JDBC_DRIVER);
        conn = DriverManager.getConnection(DB_URL,USER,PASS);

        stmt = conn.createStatement();
        String sql;
        sql = "select * from game_level\n" +
                "where level = "+2;
        ResultSet rs = stmt.executeQuery(sql);

        // 展开结果集数据库
        while(rs.next()){
            // 通过字段检索
            dgUtils.ELEMENTSIZE = rs.getInt("unit_size");
            dgUtils.SCREENWIDTH = rs.getInt("scene_width");
            dgUtils.SCREENHEIGHT = rs.getInt("scene_length");
            dgUtils.ROWCOUNT = rs.getInt("row_count");
            dgUtils.COLCOUNT = rs.getInt("col_count");
        }
        // 完成后关闭
        rs.close();
        conn.close();
        stmt.close();
        getChildren().clear();
        map.clear();
        boundMap.clear();
        tempStart = null;
        tempEnd = null;
        createWithMap(randomRowList,randomColList);
    }
    public dgServiceImpl(List<Integer> randomRowList,List<Integer> randomColList,Socket socket) throws Exception {
        Connection conn = null;
        Statement stmt = null;

        // 注册 JDBC 驱动
        Class.forName(JDBC_DRIVER);
        conn = DriverManager.getConnection(DB_URL,USER,PASS);

        stmt = conn.createStatement();
        String sql;
        sql = "select * from game_level\n" +
                "where level = "+3;
        ResultSet rs = stmt.executeQuery(sql);

        // 展开结果集数据库
        while(rs.next()){
            // 通过字段检索
            dgUtils.ELEMENTSIZE = rs.getInt("unit_size");
            dgUtils.SCREENWIDTH = rs.getInt("scene_width");
            dgUtils.SCREENHEIGHT = rs.getInt("scene_length");
            dgUtils.ROWCOUNT = rs.getInt("row_count");
            dgUtils.COLCOUNT = rs.getInt("col_count");
        }
        // 完成后关闭
        rs.close();
        conn.close();
        stmt.close();
        this.socket = socket;
        getChildren().clear();
        map.clear();
        boundMap.clear();
        tempStart = null;
        tempEnd = null;
        createWithMap(randomRowList,randomColList);
    }
    public void createWithMap(List<Integer> randomRowList,List<Integer> randomColList){
        setTranslateX(dgUtils.xOffset);
        setTranslateY(dgUtils.yOffset);
        for (int row = -1; row <= dgUtils.ROWCOUNT; row++) {
            for (int col = -1; col <= dgUtils.COLCOUNT; col++) {
                // 设置最外层移动点(注意最外层没有Unit图标，只有移动点，用于实现消除单元格是的动画效果)
                if (row == -1 || row == dgUtils.ROWCOUNT || col == -1
                        || col == dgUtils.COLCOUNT) {
                    double startX = col * (dgUtils.ELEMENTSIZE + 5) + 60;
                    double startY = row * (dgUtils.ELEMENTSIZE + 5) + 60;
                    dgBound bound = new dgBound(startX, startY, startX
                            + dgUtils.ELEMENTSIZE, startY + dgUtils.ELEMENTSIZE);
                    dgPoint point = new dgPoint(row, col);
                    boundMap.put(point, bound);
                }// 其它点都有对应的Unit图标
                else {
                    dgPoint point = new dgPoint(row, col);
                    dgTile unit = new dgTile(this, point, dgUtils.Images.get((row
                            * dgUtils.COLCOUNT + col)
                            //% dgUtils.IMAGE_NAMES.length]);
                            % dgUtils.COLCOUNT));
                    unit.socket = this.socket;
                    getChildren().add(unit);
                    Bounds bounds = unit.getBoundsInParent();
                    dgBound bound = new dgBound(bounds.getMinX(), bounds.getMinY(),
                            bounds.getMaxX(), bounds.getMaxY());
                    boundMap.put(point, bound);
                    map.put(unit.getPoint(), unit);
                }
            }
        }
        // 随机打乱图标
        for (int row = 0; row < dgUtils.ROWCOUNT; row++) {
            for (int col = 0; col < dgUtils.COLCOUNT; col++) {
                int randomRow = randomRowList.get((row+1)*(col+1)-1);
                int randomCol = randomColList.get((row+1)*(col+1)-1);

                dgTile unit = (dgTile) getChildren()
                        .get(row * dgUtils.COLCOUNT + col);
                dgTile randomUnit = (dgTile) getChildren().get(
                        randomRow * dgUtils.COLCOUNT + randomCol);
                dgPoint randomIndex = randomUnit.getPoint();
                randomUnit.index.set(unit.getPoint());
                unit.index.set(randomIndex);
                map.put(randomUnit.getPoint(), randomUnit);
                map.put(unit.getPoint(), unit);
            }
        }
    }
    // 动态刷新界面
    public void refresh() {
        List<KeyValue> values = new LinkedList<>();

        // 随机交互两个Unit图标的位置
        for (dgPoint point : map.keySet()) {
            dgTile unit = map.get(point);
            int randomNum = new Random().nextInt(map.size());
            dgTile randomUnit = (dgTile) this.getChildren().get(randomNum);
            dgPoint randomTempIndex = randomUnit.tempPoint;
            randomUnit.tempPoint = unit.tempPoint;
            unit.tempPoint = randomTempIndex;
        }
        for (dgPoint point : map.keySet()) {
            dgTile unit = map.get(point);
            KeyValue valueX = new KeyValue(unit.translateXProperty(),
                    unit.tempPoint.col * (dgUtils.ELEMENTSIZE + 5) + 60,
                    Interpolator.EASE_IN);
            KeyValue valueY = new KeyValue(unit.translateYProperty(),
                    unit.tempPoint.row * (dgUtils.ELEMENTSIZE + 5) + 60,
                    Interpolator.EASE_IN);
            values.add(valueX);
            values.add(valueY);
        }
        // 动画实现交互过程
        Timeline timeline = new Timeline();
        timeline.setCycleCount(1);

        KeyFrame frame = new KeyFrame(Duration.seconds(1.5),
                values.toArray(new KeyValue[0]));
        timeline.getKeyFrames().add(frame);
        timeline.setOnFinished(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                for (Node node : getChildren()) {
                    if (node instanceof dgTile) {
                        dgTile unit = (dgTile) node;
                        unit.index.set(unit.tempPoint);
                        map.put(unit.getPoint(), unit);
                    }
                }
            }
        });
        timeline.play();
    }

    //初始化游戏
    public void initGame() {
        getChildren().clear();
        map.clear();
        boundMap.clear();
        tempStart = null;
        tempEnd = null;
        create();
    }

    // 提示功能
    public void search() {
        for (dgPoint startPoint : map.keySet()) {
            tempStart = map.get(startPoint);
            // 遍历存在的Uint
            for (dgPoint endPoint : map.keySet()) {
                tempEnd = map.get(endPoint);
                if (tempStart != tempEnd
                        && tempStart.getType().equals(tempEnd.getType())) {
                    List<dgPoint> list = findPath(startPoint, endPoint);
                    if (list != null) {
                        // 高亮显示查找结果
                        Glow glow = new Glow(0);
                        tempStart.setEffect(glow);
                        tempEnd.setEffect(glow);
                        tempStart = null;
                        tempEnd = null;
                        Timeline time = new Timeline();
                        KeyValue value = new KeyValue(glow.levelProperty(), 1);
                        KeyFrame frame = new KeyFrame(Duration.seconds(1),
                                value);
                        time.getKeyFrames().add(frame);
                        time.setAutoReverse(true);
                        time.setCycleCount(10);
                        time.play();
                        return;
                    }
                }
            }
        }
    }

    public void create() {
        setTranslateX(dgUtils.xOffset);
        setTranslateY(dgUtils.yOffset);
        for (int row = -1; row <= dgUtils.ROWCOUNT; row++) {
            for (int col = -1; col <= dgUtils.COLCOUNT; col++) {
                // 设置最外层移动点(注意最外层没有Unit图标，只有移动点，用于实现消除单元格是的动画效果)
                if (row == -1 || row == dgUtils.ROWCOUNT || col == -1
                        || col == dgUtils.COLCOUNT) {
                    double startX = col * (dgUtils.ELEMENTSIZE + 5) + 60;
                    double startY = row * (dgUtils.ELEMENTSIZE + 5) + 60;
                    dgBound bound = new dgBound(startX, startY, startX
                            + dgUtils.ELEMENTSIZE, startY + dgUtils.ELEMENTSIZE);
                    dgPoint point = new dgPoint(row, col);
                    boundMap.put(point, bound);
                }// 其它点都有对应的Unit图标
                else {
                    dgPoint point = new dgPoint(row, col);
                    dgTile unit = new dgTile(this, point, dgUtils.Images.get((row
                            * dgUtils.COLCOUNT + col)
                            //% dgUtils.IMAGE_NAMES.length]);
                            % dgUtils.COLCOUNT));
                    getChildren().add(unit);
                    Bounds bounds = unit.getBoundsInParent();
                    dgBound bound = new dgBound(bounds.getMinX(), bounds.getMinY(),
                            bounds.getMaxX(), bounds.getMaxY());
                    boundMap.put(point, bound);
                    map.put(unit.getPoint(), unit);
                }
            }
        }
        // 随机打乱图标
        Random random = new Random();
        for (int row = 0; row < dgUtils.ROWCOUNT; row++) {
            for (int col = 0; col < dgUtils.COLCOUNT; col++) {
                int randomRow = random.nextInt(dgUtils.ROWCOUNT);
                int randomCol = random.nextInt(dgUtils.COLCOUNT);
                doubleGameData.randomRowList.add(randomRow);
                doubleGameData.randomColList.add(randomCol);
                dgTile unit = (dgTile) getChildren()
                        .get(row * dgUtils.COLCOUNT + col);
                dgTile randomUnit = (dgTile) getChildren().get(
                        randomRow * dgUtils.COLCOUNT + randomCol);
                dgPoint randomIndex = randomUnit.getPoint();
                randomUnit.index.set(unit.getPoint());
                unit.index.set(randomIndex);
                map.put(randomUnit.getPoint(), randomUnit);
                map.put(unit.getPoint(), unit);
            }
        }
        // 将初始值给服务端的data
        doubleGameData.dgBoundMap = this.boundMap;
        doubleGameData.dgMap = this.map;

    }
    // 查找可行解
    public List<dgPoint> findPath(dgPoint start, dgPoint end) {
        // 此处的start和end是指用户选取的第一个点与第二个点

        // count是为了后续判断应该向何处遍历
        start.count = -1;
        end.count = -1;
        // 清除可行解的列表
        resultPath.clear();
        // 将开始位置加入resultPath
        resultPath.add(start);
        dgPoint curPoint = null;
        dgPoint neighbor = null;

        // 存储所有可行的连接路径，方便后面选择最优解
        List<LinkedList<dgPoint>> resultList = new ArrayList<>();

        // 当resultPath中节点不为空的时候，进行一个dfs的遍历，得到所有可行解
        while (!resultPath.isEmpty()) {
            curPoint = resultPath.getLast();
            neighbor = getNextNeighbor(curPoint);
            // 有邻居节点时继续查找
            if (neighbor != null) {
                // 邻居节点为目标节点，说明路径查找成功
                if (neighbor.equals(end)) {
                    resultPath.addLast(neighbor);

                    // resultList中存储所有的可行解
                    resultList.add(new LinkedList<>(resultPath));

                    resultPath.removeLast();
                } else {
                    resultPath.addLast(neighbor);
                    boolean flag = checkCornerLessthan2(resultPath);
                    // 判断加入节点后，连接路径转弯是否大于2，如果大于2说明路径不符合要求
                    // 因为连连看的游戏规则要求不能有超过两个折线
                    if (!flag) {
                        resultPath.removeLast();
                    }
                }
            }
            // 没有邻居节点时，将该节点从resultPath中删除，继续遍历上一个节点
            else {
                resultPath.removeLast();
            }
        }
        return chooseResult(resultList);
    }

    // 选择最优连接路径
    public List<dgPoint> chooseResult(List<LinkedList<dgPoint>> resultList) {
        if (resultList.isEmpty()) {
            return null;
        }
        // 根据节点数排序，因为每条路径里的节点都是相邻节点，因此节点数就代表路径长度
        Collections.sort(resultList, new Comparator<List<dgPoint>>() {
            @Override
            public int compare(List<dgPoint> o1, List<dgPoint> o2) {
                return o1.size() - o2.size();
            }
        });
        for (List<dgPoint> path : resultList) {
            boolean flag = checkCornerLessthan2(path);
            if (flag) {
                return path;
            }
        }

        return null;
    }

    public dgPoint getNextNeighbor(dgPoint point) {
        // 为了不重复获取邻居节点，每获取一次邻居节点，获取次数加1，
        point.count++;
        int row = point.row;
        int col = point.col;
        dgTile neighbor = null;
        // 默认从左开始进行查找
        if (point.count == 0) {
            dgPoint left = new dgPoint(row, col - 1);
            neighbor = map.get(left);
            //邻居是目标位置,返回该位置
            if (neighbor == tempEnd) {
                return left;
            }
            //邻居位置为空,且不在包含的路径中(避免回路),返回该位置
            if (neighbor == null && (col - 1) >= -1
                    && !resultPath.contains(left)) {
                return left;
            } else {
                neighbor = null;
                point.count++;
            }
        }
        //count=1时向右寻路
        if (point.count == 1) {
            dgPoint right = new dgPoint(row, col + 1);
            neighbor = map.get(right);
            if (neighbor == tempEnd) {
                return right;
            }
            if (neighbor == null && (col + 1) <= dgUtils.COLCOUNT
                    && !resultPath.contains(right)) {
                return right;
            } else {
                neighbor = null;
                point.count++;
            }
        }
        //count=2时向上寻路
        if (point.count == 2) {
            dgPoint up = new dgPoint(row - 1, col);
            neighbor = map.get(up);
            if (neighbor == tempEnd) {
                return up;
            }
            if (neighbor == null && (row - 1) >= -1 && !resultPath.contains(up)) {
                return up;
            } else {
                neighbor = null;
                point.count++;
            }
        }
        //count=3时向下寻路
        if (point.count == 3) {
            dgPoint down = new dgPoint(row + 1, col);
            neighbor = map.get(down);
            if (neighbor == tempEnd) {
                return down;
            }
            if (neighbor == null && (row + 1) <= dgUtils.ROWCOUNT
                    && !resultPath.contains(down)) {
                return down;
            } else {
                neighbor = null;
                point.count++;
            }
        }

        return null;
    }
    public boolean checkCornerLessthan2(List<dgPoint> path) {
        //小于4个点，拐弯肯定<=2
        if (path.size() <= 4) {
            return true;
        } else {
            int cross = 0;
            for (int i = 0; i < path.size() - 2; i++) {
                dgPoint first = path.get(i);
                dgPoint second = path.get(i + 1);
                dgPoint third = path.get(i + 2);
                int dx1 = second.col - first.col;
                int dx2 = third.col - second.col;
                int dy1 = second.row - first.row;
                int dy2 = third.row - second.row;
                //判断连续3个点是否在一条直线上
                if (dx1 != dx2 || dy1 != dy2) {
                    cross++;
                }
            }
            if (cross <= 2) {
                return true;
            } else {
                return false;
            }
        }
    }
    public void drawLine(final List<dgPoint> path) {
        final dgTile start = map.get(path.get(0));
        final dgTile end = map.get(path.get(path.size() - 1));
        Path track = new Path();
        //将查找到中的点加入Path对象中
        for (int i = 0; i < path.size(); i++) {
            dgBound bound = boundMap.get(path.get(i));
            double centerX = (bound.getStartX() + bound.getEndX()) / 2;
            double centerY = (bound.getStartY() + bound.getEndY()) / 2;
            if (i == 0) {
                track.getElements().add(new MoveTo(centerX, centerY));
            } else {
                track.getElements().add(new LineTo(centerX, centerY));
            }
        }
        Duration duration = Duration.seconds(0.1 * path.size());

        // 位置变换特效
        PathTransition pathTransition = PathTransitionBuilder.create()
                .node(start).orientation(PathTransition.OrientationType.ORTHOGONAL_TO_TANGENT)
                .path(track).duration(duration).build();
        pathTransition.setOnFinished(new EventHandler<ActionEvent>() {

            @Override
            public void handle(ActionEvent event) {
                System.out.println(getChildren().remove(start));
                System.out.println(getChildren().remove(end));
                System.out.println(map.remove(start.getPoint()));
                map.remove(end.getPoint());
                if (getChildren().isEmpty() && Goals.goals>4) {
                    //dgClock.flag=0;
                    Text text = new Text("恭喜您获胜!\n您的得分为:"+Goals.goals+"分");

                    final WebView browser = new WebView();
                    final WebEngine webEngine = browser.getEngine();

                    String url = LinkGameApplication.class.getResource("view/index.html").toExternalForm();
                    webEngine.load(url);
                    ScrollPane scrollPane = new ScrollPane();
                    scrollPane.setContent(browser);
                    getChildren().add(scrollPane);

                    text.setTranslateX(dgUtils.SCREENWIDTH / 2 -200);
                    System.out.println(dgUtils.SCREENWIDTH);
                            //- dgUtils.CONTROLWIDTH / 2);
                    text.setTranslateY(dgUtils.SCREENHEIGHT / 2-100);
                    text.setFont(javafx.scene.text.Font.font(32));
                    text.setFill(Color.WHITE);
                    getChildren().add(text);
                    try{
                        Connection conn = null;
                        Statement stmt = null;

                        // 注册 JDBC 驱动
                        Class.forName(JDBC_DRIVER);
                        conn = DriverManager.getConnection(DB_URL,USER,PASS);

                        stmt = conn.createStatement();
                        String sql;
                        Date date = new Date();
                        SimpleDateFormat dateFormat= new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
                        System.out.println(dateFormat.format(date));
                        sql = "insert into game_history values(null,\""+dateFormat.format(date)+"\","+
                                "\""+user.getUsername()+"\",\""+userGameView.enemy.getUsername()+"\""+",\"3\")";
                        System.out.println(sql);
                        int rs = stmt.executeUpdate(sql);

                        String updateSql = "Update user set user_goal = user_goal+"+(2*Goals.goals-8)
                                +" where username = \""+user.getUsername()+"\"";
                        System.out.println(updateSql);
                        int us = stmt.executeUpdate(updateSql);
                        conn.close();
                        stmt.close();
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                }else if(getChildren().isEmpty() && Goals.goals<4){
                    Text text = new Text("很遗憾!\n您的得分为:"+Goals.goals+"分,输给了对手，再接再励！");
                    text.setTranslateX(dgUtils.SCREENWIDTH / 2 -200);
                    System.out.println(dgUtils.SCREENWIDTH);
                    text.setTranslateY(dgUtils.SCREENHEIGHT / 2-100);
                    text.setFont(javafx.scene.text.Font.font(32));
                    text.setFill(Color.BLACK);
                    getChildren().add(text);
                    try{
                        Connection conn = null;
                        Statement stmt = null;

                        // 注册 JDBC 驱动
                        Class.forName(JDBC_DRIVER);
                        conn = DriverManager.getConnection(DB_URL,USER,PASS);

                        stmt = conn.createStatement();
                        String updateSql = "Update user set user_goal = user_goal -"+(8-2*Goals.goals)
                                +" where username = \""+user.getUsername()+"\"";
                        int us = stmt.executeUpdate(updateSql);
                        conn.close();
                        stmt.close();
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                }else if(getChildren().isEmpty() && Goals.goals==4){
                    Text text = new Text("平局!\n您的得分为:"+Goals.goals+"分,再接再励！");

/*                    final WebView browser = new WebView();
                    final WebEngine webEngine = browser.getEngine();

                    String url = test3.class.getResource("view/lose.html").toExternalForm();
                    webEngine.load(url);
                    ScrollPane scrollPane = new ScrollPane();
                    scrollPane.setContent(browser);
                    getChildren().add(scrollPane);*/

                    text.setTranslateX(dgUtils.SCREENWIDTH / 2 -200);
                    System.out.println(dgUtils.SCREENWIDTH);
                    //- dgUtils.CONTROLWIDTH / 2);
                    text.setTranslateY(dgUtils.SCREENHEIGHT / 2-100);
                    text.setFont(javafx.scene.text.Font.font(32));
                    text.setFill(Color.BLACK);
                    getChildren().add(text);
                }
            }
        });
        // 实现选择特效
        RotateTransition rotateTransition = RotateTransitionBuilder.create()
                .duration(duration).byAngle(360 * path.size()).build();
        // 并行执行
        ParallelTransition parallelTransition = new ParallelTransition();
        parallelTransition.setNode(start);
        parallelTransition.getChildren().addAll(pathTransition,
                rotateTransition);
        parallelTransition.play();
    }
}
